#pragma once
#include "trace.h"
#include "bpu.h"
// #include <boost/lockfree/spsc_queue.hpp>
#include "buffer.h"

typedef struct
{
    OP *op;
    bool bpred_miss;
    BPU_Res bpu_res;
} FrontendOP;

class Frontend {
public:
    virtual void update(word_t addr, BPU_Res correct_res) = 0;
    virtual void redirect(word_t addr, BPU_Res correct_res) = 0;
    virtual FrontendOP fetch_op() = 0;
    virtual void run() = 0;
    virtual void reset() = 0;
    virtual void print_counter() = 0;
    virtual void print_status() = 0;
};

class IdealFrontend : public Frontend
{
public:
    IdealFrontend() {}
    ~IdealFrontend() {}
    void update(word_t addr, BPU_Res correct_res) override {}
    void redirect(word_t addr, BPU_Res correct_res) override {}
    FrontendOP fetch_op() override
    {
        auto op = read_op();
        FrontendOP fop = {.op = op, .bpred_miss = false, .bpu_res = {0}};
        return fop;
    }
    void run() override {}
    void reset() override {}
    void print_counter() override {}
    void print_status() override {}
};
class NormalFrontend : public Frontend
{
public:
    uint64_t cycle = 0;
    typedef struct
    {
        OP *op;
        bool bpred_miss;
        BPU_Res bpu_res;
        uint64_t cycle;
    } IBUF_Entry;

    FIFO<IBUF_Entry> ibuf;
    struct
    {
        word_t pc;
        std::list<OP *> fetching_ops;
        bool wrong_path;
        size_t wrong_op_num;
        word_t correct_pc;
    } state;

    BPU bpu;
    Counter ras_miss, ras_hit;
    Counter bimodal_miss, bimodal_hit;
    Counter btb_miss, btb_hit;
    Counter total_miss, total_hit;
    Counter unpredict_miss, unpredict_hit;
    Counter error_predict_miss;
    Counter ibuf_full;
    NormalFrontend();
    ~NormalFrontend();
    void update(word_t addr, BPU_Res correct_res) override;
    void redirect(word_t addr, BPU_Res correct_res) override;
    FrontendOP fetch_op() override;
    void run() override;
    void reset() override;
    void print_counter() override;
    void print_status() override;
};
